package com.jzqf.wheel;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 圆形菜单，按与圆心夹角滑动
 * 相邻条目中心点与圆心夹角一致
 * 2020/3/31 10:20
 *
 * @author LiuWeiHao
 * Email 872235631@qq.com
 */
public class CircleListView extends View {
    private final String TAG = CircleListView.class.getName();
    /**
     * 相邻条目中心点与圆心的夹角
     */
    private final float ITEM_ANGLE = 7;
    /**
     * 外圆半径
     */
    private int mOutWheelRadius;
    /**
     * 内圆半径
     */
    private int mInWheelRadius;
    /**
     * 条目中心点所在圆的半径
     */
    private int mItemCenterRadius;
    private int mItemImgWidth;
    private int mOffSetX;
    private int mCenterX;//圆心的x轴坐标
    private int mCenterY;//圆心的y轴坐标
    private float mLastY;//上一次触摸的y轴位置
    private float mDownY;
    private float mLastX = 0;
    /**
     * 检测按下到抬起时旋转的角度,以圆心所在水平线，向上为负，向下为正
     */
    private double mTmpAngle;
    private Bitmap mBitmapWheel = null;
    private List<WheelItem> mDatas;
    private List<Point> mPointCenterList;
    private List<Point> mPointCenterOldList;
    private List<Rect> mItemRectList;
    private List<Rect> mItemImgRectList;
    private List<Point> mItemTxtPointList;
    private Paint mWeelPaint;
    private Rect mBitmapWheelSrc;
    private Rect mBitmapWheelDst;
    private final double IMG_ZOOM = 1.2;
    private boolean isDataChange = false;

    public CircleListView(Context context) {
        super(context);
    }

    public CircleListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleListView);
        mOutWheelRadius = typedArray.getDimensionPixelSize(R.styleable.CircleListView_outwheelRadius, 0);
        mInWheelRadius = typedArray.getDimensionPixelSize(R.styleable.CircleListView_inWheelRadius, 0);
        mItemCenterRadius = typedArray.getDimensionPixelSize(R.styleable.CircleListView_itemCenterRadius, 0);
        mBitmapWheel = BitmapFactory.decodeResource(getResources(), typedArray.getResourceId(R.styleable.CircleListView_circleDrawable, 0));
        mOffSetX = typedArray.getDimensionPixelSize(R.styleable.CircleListView_offSetX, 0);
        mItemImgWidth = typedArray.getDimensionPixelSize(R.styleable.CircleListView_itemImgWidth, 0);
        typedArray.recycle();
    }

    public List<WheelItem> getDatas() {
        return mDatas;
    }

    public void setDatas(List<WheelItem> datas) {
        this.mDatas = datas;
        setDefaultSelectPosition(1);
        isDataChange = true;
        refresh();
    }

    private int getMidSelect() {
        int mid;
        if (mDatas.size() % 2 == 1) {
            mid = (mDatas.size() + 1);
        } else {
            mid = mDatas.size() / 2;
        }
        return mid;
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        Log.i(TAG, "onLayout start");
        mCenterY = getHeight() / 2;
        mCenterX = getWidth() + mOffSetX;
        onLayoutItemCenter();
//        Log.i(TAG, "onLayoutItemCenter");
        onLayoutItemCenterMove();
//        Log.i(TAG, "onLayoutItemCenterMove");
        //14-17ms
        onLayoutItem();
//        Log.i(TAG, "onLayoutItem");
    }

    private void onLayoutItem() {
        if (mItemImgRectList == null) {
            mItemImgRectList = new ArrayList<>();
        } else {
            mItemImgRectList.clear();
        }
        if (mItemTxtPointList == null) {
            mItemTxtPointList = new ArrayList<>();
        } else {
            mItemTxtPointList.clear();
        }
        mItemRectList = new ArrayList<>();
        int selectPosition = getSelectPosition();
        double zoom = 1.4;
        int itemRadius = mItemImgWidth / 2;
        for (int i = 0; i < mPointCenterList.size(); i++) {
            Point pointCenter = mPointCenterList.get(i);
            //计算图片区域
            Rect rectItem = new Rect();
            Rect rectImg = new Rect();
            Point pointTxt = new Point();
            if (i == selectPosition) {
                rectImg.left = (int) (pointCenter.x - itemRadius * zoom);
                rectImg.top = (int) (pointCenter.y - itemRadius * zoom);
                rectImg.right = (int) (pointCenter.x + itemRadius * zoom);
                rectImg.bottom = (int) (pointCenter.y + itemRadius * zoom);
            } else {
                rectImg.left = pointCenter.x - itemRadius;
                rectImg.top = pointCenter.y - itemRadius;
                rectImg.right = pointCenter.x + itemRadius;
                rectImg.bottom = pointCenter.y + itemRadius;
            }
            pointTxt.x = rectImg.right + 10;
            pointTxt.y = pointCenter.y + 10;
            rectItem.left = rectImg.left;
            rectItem.top = rectImg.top;
            rectItem.right = pointTxt.x + 90;
            rectItem.bottom = rectImg.bottom;
            mItemImgRectList.add(rectImg);
            mItemTxtPointList.add(pointTxt);
            mItemRectList.add(rectItem);
        }
    }

    private void onLayoutItemCenterMove() {
        //数据源改变时重新加入初始坐标，遍历计算改变后的位置
        if (isDataChange) {
            mPointCenterList = new ArrayList<>(mDatas.size());
            mPointCenterList.addAll(mPointCenterOldList);
        }
        isDataChange = false;
        int xDistance = (int) (mItemCenterRadius * Math.sin(Math.toRadians(mTmpAngle)));
        for (Point point : mPointCenterList) {
            point.y = point.y + xDistance;
            point.x = (int) (mCenterX - Math.sqrt(Math.pow(mItemCenterRadius, 2) - Math.pow(point.y - mCenterY, 2)));
        }
    }

    private int mDefaultSelectPosition;

    public void setDefaultSelectPosition(int defaultSelectPosition) {
        if (defaultSelectPosition >= 0 && defaultSelectPosition < mDatas.size()) {
            this.mDefaultSelectPosition = defaultSelectPosition;
        } else {
            mDefaultSelectPosition = 0;
        }
    }

    private void onLayoutItemCenter() {
        //数据源改变时重新计算初始坐标
        if (!isDataChange) {
            return;
        }
        mPointCenterOldList = new ArrayList<>(mDatas.size());
        //线距离水平线的高度从中心线向上，等差数列增加
        for (int position = 0; position < mDatas.size(); position++) {
            Point pointCenterOld = new Point();
            //角度
            float angle = ITEM_ANGLE * (position - mDefaultSelectPosition);
            int itemCenteroHorizontalLine = (int) (mItemCenterRadius * Math.sin(Math.toRadians(angle)));
            pointCenterOld.y = mCenterY + itemCenteroHorizontalLine;
            pointCenterOld.x = (int) (mCenterX - Math.sqrt(Math.pow(mItemCenterRadius, 2) - Math.pow(itemCenteroHorizontalLine, 2)));

            mPointCenterOldList.add(pointCenterOld);
        }
        Collections.sort(mPointCenterOldList, (o1, o2) -> Integer.compare(o1.y, o2.y));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBitmap(canvas);
        drawItems(canvas);
//        drawTest(canvas);
        Log.i(TAG, "onDraw drawItems----");
    }

    /**
     * 绘制背景图
     */
    private void drawBitmap(Canvas canvas) {
        if (mBitmapWheel == null) {
            return;
        }
        if (mWeelPaint == null) {
            mWeelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mWeelPaint.setAlpha(100);
        }
        if (mBitmapWheelSrc == null) {
            mBitmapWheelSrc = new Rect(0, 0, mBitmapWheel.getWidth(), mBitmapWheel.getHeight());
        }
        if (mBitmapWheelDst == null) {
            mBitmapWheelDst = new Rect(getWidth() - mBitmapWheel.getWidth(), 0, getWidth(), getHeight());
        }
        canvas.drawBitmap(mBitmapWheel, mBitmapWheelSrc, mBitmapWheelDst, mWeelPaint);
    }

    private void drawTest(Canvas canvas) {
        //测试辅助线
        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        paint.setAlpha(80);
        paint.setStrokeWidth(2f);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(mCenterX, mCenterY, mOutWheelRadius, paint);
        canvas.drawCircle(mCenterX, mCenterY, mInWheelRadius, paint);
        canvas.drawCircle(mCenterX, mCenterY, mItemCenterRadius, paint);
        int i = 0;
        for (Point point : mPointCenterOldList) {
            canvas.drawCircle(point.x, point.y, 15, paint);
            i++;
        }
        paint.setColor(Color.RED);
        for (Point point : mPointCenterList) {
            canvas.drawCircle(point.x, point.y, 5, paint);
        }
        for (Rect rect : mItemRectList) {
            canvas.drawRect(rect, paint);
        }
    }

    private void drawItems(Canvas canvas) {
        Paint paintImg = new Paint();
        paintImg.setAntiAlias(true);
        paintImg.setFilterBitmap(true);
        Paint paintTxt = new Paint();
        paintTxt.setStyle(Paint.Style.FILL);
        paintTxt.setTextSize(20f);
        paintTxt.setColor(Color.WHITE);
//        int selectPosition = getSelectPosition();
        for (int index = 0; index < mDatas.size(); index++) {
            WheelItem wheelItem = mDatas.get(index);
            Bitmap bitmap = wheelItem.getBitmap();
            //用来截取Bitmap局部所想要显示的像素块区域，通过构造方法中的四个坐标系点确定范围。这个参数可以为null，为null就是整个Bitmap都作为目标资源显示
//            Rect rectSrc = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            //用来显示的区域，在控件中绘制Bitmap的区域，可以实现拉伸或者缩放
            Rect rectDst = mItemImgRectList.get(index);
            //被选中的条目设置为高亮，其他透明度降低
            Point pointTxt = mItemTxtPointList.get(index);
//            if (index == selectPosition) {
//                paintImg.setAlpha(255);
//                paintTxt.setAlpha(255);
//            } else {
//                paintImg.setAlpha(100);
//                paintTxt.setAlpha(100);
//            }
            canvas.drawBitmap(bitmap, null, rectDst, paintImg);
            canvas.drawText(wheelItem.getDesc(), pointTxt.x, pointTxt.y, paintTxt);
        }
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDownY = event.getY();
                mLastX = event.getX();
                mLastY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                double start = MathUtil.getAngleToY(mLastX, mLastY, mCenterX, mCenterY);
                double end = MathUtil.getAngleToY(event.getX(), event.getY(), mCenterX, mCenterY);
                mTmpAngle = end - start;
//                Log.i(TAG, "start=" + start + ",end=" + end + ",tempAngle=" + mTmpAngle);
                // 重新布局
                if (canAngle(mTmpAngle) && mTmpAngle != 0) {
                    requestLayout();
                    invalidate();
                }
                mLastX = event.getX();
                mLastY = event.getY();
                break;
            case MotionEvent.ACTION_UP:
                //移动距离<条目高度的一半时，定义为点击事件
                if (mOnItemClickListener != null
                        && Math.abs(event.getY() - mDownY) < mItemImgWidth / 2) {
                    int clickPositon = getClickPositon(event.getX(), event.getY());
                    if (clickPositon > -1) {
                        mOnItemClickListener.onItemClick(CircleListView.this, clickPositon);
//                        setPosition(clickPositon);
//                        Handler handler = new Handler();
//                        handler.postDelayed(new Runnable() {
//                            @Override
//                            public void run() {
////                                mOnItemClickListener.onItemClick(CircleListView.this, clickPositon);
//                            }
//                        }, 500);
                    }
                }
                //移动距离>=条目高度的一半时，定义为滚动事件
                if (mOnAngleSelectListener != null
                        && Math.abs(event.getY() - mDownY) >= mItemImgWidth / 2) {
                    int position = getSelectPosition();
                    if (position > -1) {
//                        startAnimation(position);
                        mOnAngleSelectListener.onAngleSelect(CircleListView.this, position);
                    }
                }
                break;
            default:
                break;
        }
        return true;
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    private boolean isInWheel(float x, float y) {
        if (x >= mCenterX - mOutWheelRadius) {
            int touchrsqr = (int) (x * x + y * y);
            return touchrsqr >= mInWheelRadius * mInWheelRadius && touchrsqr <= mOutWheelRadius * mOutWheelRadius;
        }
        return false;
    }


    private boolean canAngle(double angle) {
        boolean canAngle=true;
        Point pointTop = mPointCenterList.get(0);
        Point pointBottom = mPointCenterList.get(mPointCenterList.size() - 1);
        int xDistance = (int) (mItemCenterRadius * Math.sin(Math.toRadians(angle)));
        if (angle < 0) {
            canAngle = mCenterY <= pointBottom.y - Math.abs(xDistance);
        } else {
//            canAngle = mCenterY >= pointTop.y + Math.abs(xDistance);
        }
        return canAngle;
    }

    private void refresh() {
        requestLayout();
        invalidate();
    }

    public int getSelectPosition() {
        int position = 0;
        if (mPointCenterList == null) {
            return position;
        }
        //最小距离
        double sinItemY = mItemCenterRadius * Math.sin(Math.toRadians(ITEM_ANGLE / 2));
        for (int index = 0; index < mPointCenterList.size(); index++) {
            if (Math.abs(mPointCenterList.get(index).y - mCenterY) < sinItemY) {
                position = index;
                break;
            }
        }
        return position;
    }

    /**
     * 根据坐标点判断被选中的条目位置
     *
     * @param x 坐标点X
     * @param y 坐标点Y
     * @return 被选中条目的位置
     */
    private int getClickPositon(float x, float y) {
        int position = -1;
        for (int index = 0; index < mItemRectList.size(); index++) {
            Rect rectIndex = mItemRectList.get(index);
            if (rectIndex.contains((int) x, (int) y)) {
                position = index;
                break;
            }
        }
        return position;
    }

    private float mLastAnimateValue = 0;

    protected void startAnimation(int position) {
        float angle = MathUtil.getAngle(mCenterX - mItemCenterRadius, mCenterY, mCenterX, mCenterY)
                - MathUtil.getAngle(mPointCenterList.get(position).x, mPointCenterList.get(position).y, mCenterX, mCenterY);
        ValueAnimator animator = ValueAnimator.ofFloat(0, angle);
        animator.setDuration(500);
        animator.addUpdateListener(valueAnimator -> {
            float animatedValue = (float) valueAnimator.getAnimatedValue();
            mTmpAngle = animatedValue - mLastAnimateValue;
            mLastAnimateValue = animatedValue;
            refresh();
        });
        animator.setInterpolator(new DecelerateInterpolator());
        animator.start();
    }


    private OnItemClickListener mOnItemClickListener;
    private OnAngleSelectListener mOnAngleSelectListener;

    public interface OnItemClickListener {
        void onItemClick(CircleListView parent, int position);
    }

    public void setOnWheelItemClickListener(OnItemClickListener listener) {
        mOnItemClickListener = listener;
    }

    public interface OnAngleSelectListener {
        void onAngleSelect(CircleListView parent, int position);
    }

    public void setOnAngleSelectListener(OnAngleSelectListener listener) {
        mOnAngleSelectListener = listener;
    }
}
